﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Data;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using PlanningGIS.Framework.Controls;
using PlanningGIS.Win.Controls;
using PlanningGIS.ArcGIS;
using PlanningGIS.Report;
using PlanningGIS.Framework;

namespace PlanningGIS.Statistics
{
    public class FeatureStat
    {
        private IFeatureClass m_pClass=null;
        private IMapControl3  m_pMap=null;

        public FeatureStat()
        {
        }

        //当前图层
        public IFeatureClass FeatureClass
        {
            get { return m_pClass; }
            set { m_pClass = value; }
        }

        //当前地图
        public IMapControl3 MapControl
        {
            get { return m_pMap; }
            set { m_pMap = value; }
        }

        //普通的要素统计
        public bool Stat(IPolygon pPolygon,StatLayer pStatLyr,string name)
        {
            try
            {
                int idx = m_pClass.FindField(pStatLyr.StatFieldName  );
                if (idx == -1)
                {
                    MsgHelper.ShowInfomationMsgbox("该层数据中未包含" + pStatLyr.StatFieldName + "字段，请加载符合要求的数据！");
                    return false;
                }
                ITopologicalOperator2 pTopo = pPolygon as ITopologicalOperator2;
                pTopo.IsKnownSimple_2 = false;
                pTopo.Simplify();
                pTopo.IsKnownSimple_2 = true;
                pPolygon.Project(((IGeoDataset)m_pClass).SpatialReference);

                DataTable pTable = CreateDatatable(pStatLyr);

                ISpatialFilter pSF = new SpatialFilterClass();
                pSF.Geometry = pPolygon;
                pSF.GeometryField = m_pClass.ShapeFieldName;
                pSF.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                pSF.WhereClause = pStatLyr.WhereClause1();
                IFeatureCursor pCursor = m_pClass.Search(pSF, false);
                IFeature pFeature = pCursor.NextFeature();
                
                while (pFeature!= null)
                {
                    AddDatarowByFeature(pTable,pFeature,pPolygon, pStatLyr);
                    pFeature = pCursor.NextFeature();
                }
                if (pTable.Rows.Count == 0)
                {
                    MsgHelper.ShowInfomationMsgbox("未检索到符合条件的要素，请重试！");
                    return false ;
                }
                FrmReport statReport = new FrmReport();
                //statReport.OnPageMouseDbClick += new DetailSectionEventHandler(OnPageMouseDoubleClick);
                statReport.DataSource = pTable;
                ReportName pName = GetReportname(name, pStatLyr);
                if (pName.HasParameter)
                {
                    IArea pArea = pPolygon as IArea;
                    double area = double.Parse(Math.Abs(pArea.Area).ToString("F3"));
                    statReport.ParameterValue = area;
                }
                statReport.FullName = AppConfig.StartupPath + @"\Report\Statistic\" + pName.Value;
                statReport.Show();
                //statReport.ShowDialog();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(pCursor);
                return true;
            }
            catch
            {
                MsgHelper.ShowInfomationMsgbox("要素统计失败！");
                return false;
            }
        }

        private DataTable CreateDatatable(StatLayer pStatLyr)
        {
            DataTable pTable = new DataTable();

            foreach (ReportField field in pStatLyr.ReportFields)
            {
                DataColumn pColumn = new DataColumn(field.Key);
                pColumn.DataType = Type.GetType("System." + field.Type);
                string str = field.Type.ToLower();
                switch (field.Type.ToLower())
                {
                    case "int":
                    case "int32":
                        pColumn.DefaultValue = 0;
                        break;
                    case "string":
                        pColumn.DefaultValue = "";
                        break;
                    case "double":
                        pColumn.DefaultValue = 0.0;
                        break;
                    case "byte[]":
                        pColumn.DefaultValue = null;
                        break;
                    default:
                        break;
                }
                pTable.Columns.Add(pColumn);
            }
            return pTable;
        }

        private void AddDatarowByFeature(DataTable pTable, IFeature pFeature, IPolygon pPy,StatLayer pStatlayer)
        {
            if (pTable == null || pFeature == null)
            {
                return;
            }

            ITopologicalOperator pTopo = pPy as ITopologicalOperator;
            DataRow pRow = pTable.NewRow();
            int idx = -1;
            foreach (ReportField pField in pStatlayer.ReportFields)
            {
                if (pField.Value == null || pField.Value.Length == 0)
                {
                    switch (pField.Key)
                    {
                        case "OID":
                            pRow["OID"] = pFeature.OID.ToString();
                            break;
                        case "LENGTH":
                            if (m_pClass.ShapeType == esriGeometryType.esriGeometryPolyline)
                            {
                                IPolyline pPl = pFeature.ShapeCopy as IPolyline;
                                pRow[pField.Key] = double.Parse(pPl.Length.ToString("F3"));
                                if (HasIntersertAttribute("LENGTH", pTable))
                                {
                                    IPolyline pTempPl = pTopo.Intersect(pPl, pPl.Dimension) as IPolyline;
                                    pRow["INTERSECTLENGTH"] = double.Parse(pTempPl.Length.ToString("F3"));
                                }
                            }
                            break;
                        case "MGRADE":
                        case "TYPE":
                            idx = pFeature.Fields.FindField(pStatlayer.StatFieldName);
                            if (idx > -1)
                            {
                                pRow[pField.Key] = GetValueType(pFeature.get_Value(idx).ToString(),pStatlayer );
                            }
                            break;
                        case "AREA":
                            if (m_pClass.ShapeType == esriGeometryType.esriGeometryPolygon)
                            {
                                IPolygon pPolygon = pFeature.ShapeCopy as IPolygon;
                                IArea pArea = pPolygon as IArea;
                                pRow[pField.Key] = double.Parse(Math.Abs(pArea.Area).ToString("F3"));
                                if (HasIntersertAttribute("AREA", pTable))
                                {
                                    IPolygon pTempPolygon = pTopo.Intersect(pPolygon, pPolygon.Dimension) as IPolygon;
                                    pArea = pTempPolygon as IArea;
                                    pRow["INTERSECTAREA"] = double.Parse(Math.Abs(pArea.Area).ToString("F3"));
                                }
                            }
                            break;
                    }
                }
                else
                {
                    idx = pFeature.Fields.FindField(pField.Value);
                    if (idx == -1)
                    {
                        continue;
                    }
                    switch (pField.Type.ToLower())
                    {
                        case "int":
                        case "int32":
                            if ((pFeature.get_Value(idx) == null) || Convert.IsDBNull(pFeature.get_Value(idx)))
                                pRow[pField.Key ] = 0;
                            else
                                pRow[pField.Key] = int.Parse(pFeature.get_Value(idx).ToString());
                            break;
                        case "double":
                            if ((pFeature.get_Value(idx) == null) || Convert.IsDBNull(pFeature.get_Value(idx)))
                                pRow[pField.Key] = 0.000;
                            else
                                pRow[pField.Key] = double.Parse(pFeature.get_Value(idx).ToString());
                            break;
                        case "byte[]":
                            if ((pFeature.get_Value(idx) == null) || Convert.IsDBNull(pFeature.get_Value(idx)))
                                pRow[pField.Key ] = null;
                            else
                                pRow[pField.Key] = pFeature.get_Value(idx) as byte[];
                            break;
                        case "string":
                            if ((pFeature.get_Value(idx) == null) || Convert.IsDBNull(pFeature.get_Value(idx)))
                                pRow[pField.Key ] = "";
                            else
                                pRow[pField.Key] = pFeature.get_Value(idx).ToString();
                            break;
                        default:
                            break;
                    }
                }
            }
            pTable.Rows.Add(pRow);

        }

        private void AddDatarowByFeature(DataTable pTable, IFeature pFeature, IPolygon pPy, StatLayer pStatlayer,List<StatLayer> lyrs,Hashtable pHash)
        {
            if (pTable == null || pFeature == null)
            {
                return;
            }

            ITopologicalOperator pTopo = pPy as ITopologicalOperator;
            DataRow pRow = pTable.NewRow();
            int idx = -1;
            foreach (ReportField pField in pStatlayer.ReportFields)
            {
                if (pField.Value == null || pField.Value.Length == 0)
                {
                    switch (pField.Key)
                    {
                        case "OID":
                            pRow["OID"] = pFeature.OID.ToString();
                            break;
                        case "LENGTH":
                            if (m_pClass.ShapeType == esriGeometryType.esriGeometryPolyline)
                            {
                                IPolyline pPl = pFeature.ShapeCopy as IPolyline;
                                pRow[pField.Key] = double.Parse(pPl.Length.ToString("F3"));
                                if (HasIntersertAttribute("LENGTH", pTable))
                                {
                                    IPolyline pTempPl = pTopo.Intersect(pPl, pPl.Dimension) as IPolyline;
                                    pRow["INTERSECTLENGTH"] = double.Parse(pTempPl.Length.ToString("F3"));
                                }
                            }
                            break;
                        case "MGRADE":
                        case "TYPE":
                            idx = pFeature.Fields.FindField(pStatlayer.StatFieldName);
                            if (idx > -1)
                            {
                                pRow[pField.Key] = GetValueType(pFeature.get_Value(idx).ToString(), pStatlayer);
                            }
                            break;
                        case "AREA":
                            if (m_pClass.ShapeType == esriGeometryType.esriGeometryPolygon)
                            {
                                IPolygon pPolygon = pFeature.ShapeCopy as IPolygon;
                                IArea pArea = pPolygon as IArea;
                                pRow[pField.Key] = double.Parse(Math.Abs(pArea.Area).ToString("F3"));
                                if (HasIntersertAttribute("AREA", pTable))
                                {
                                    pRow["INTERSECTAREA"] = double.Parse(GetVegetableArea(pFeature.ShapeCopy as IPolygon, pHash).ToString("F3"));
                                }
                            }
                            break;
                    }
                }
                else
                {
                    idx = pFeature.Fields.FindField(pField.Value);
                    if (idx == -1)
                    {
                        continue;
                    }
                    switch (pField.Type.ToLower())
                    {
                        case "int":
                        case "int32":
                            if ((pFeature.get_Value(idx) == null) || Convert.IsDBNull(pFeature.get_Value(idx)))
                                pRow[pField.Key] = 0;
                            else
                                pRow[pField.Key] = int.Parse(pFeature.get_Value(idx).ToString());
                            break;
                        case "double":
                            if ((pFeature.get_Value(idx) == null) || Convert.IsDBNull(pFeature.get_Value(idx)))
                                pRow[pField.Key] = 0.000;
                            else
                                pRow[pField.Key] = double.Parse(pFeature.get_Value(idx).ToString());
                            break;
                        case "byte[]":
                            if ((pFeature.get_Value(idx) == null) || Convert.IsDBNull(pFeature.get_Value(idx)))
                                pRow[pField.Key] = null;
                            else
                                pRow[pField.Key] = pFeature.get_Value(idx) as byte[];
                            break;
                        case "string":
                            if ((pFeature.get_Value(idx) == null) || Convert.IsDBNull(pFeature.get_Value(idx)))
                                pRow[pField.Key] = "";
                            else
                                pRow[pField.Key] = pFeature.get_Value(idx).ToString();
                            break;
                        default:
                            break;
                    }
                }
            }
            pTable.Rows.Add(pRow);

        }

        private string GetValueType(string strCode,StatLayer pStatLyr)
        {
            if (strCode == null || strCode.Length == 0 || pStatLyr.StatCodes == null || pStatLyr.StatCodes.Count == 0)
            {
                return null;
            }
            for (int i = 0; i < pStatLyr.StatCodes.Count; i++)
            {
                if (pStatLyr.StatCodes[i].Fcode == strCode)
                {
                    return pStatLyr.StatCodes[i].Value;
                }
            }
            return null;
        }

        private bool HasIntersertAttribute(string str, DataTable pTable)
        {
            if (str == null || pTable == null || pTable.Columns.Count == 0)
            {
                return false;
            }
            string strName = "INTERSECT" + str;
            foreach (DataColumn pColumn in pTable.Columns)
            {
                if (pColumn.ColumnName == strName)
                {
                    return true;
                }
            }
            return false;
        }

        private ReportName GetReportname(string name,StatLayer pStatLyr)
        {
            if (name == null || name.Length == 0)
            {
                return null;
            }
            foreach (ReportName pName in pStatLyr.ReportNames)
            {
                if (pName.Key.Equals(name))
                {
                    return pName;
                }
            }
            return null;
        }

        //特殊统计，主要是为衢州设计
        public bool Stat(IPolygon pPolygon, StatLayer pStatLyr, List<StatLayer> lyrs, string name,Hashtable pHash)
        {
            try
            {
                int idx = m_pClass.FindField(pStatLyr.StatFieldName);
                if (idx == -1)
                {
                    MsgHelper.ShowInfomationMsgbox("该层数据中未包含" + pStatLyr.StatFieldName + "字段，请加载符合要求的数据！");
                    return false;
                }
                ITopologicalOperator2 pTopo = pPolygon as ITopologicalOperator2;
                pTopo.IsKnownSimple_2 = false;
                pTopo.Simplify();
                pTopo.IsKnownSimple_2 = true;
                pPolygon.Project(((IGeoDataset)m_pClass).SpatialReference);

                DataTable pTable = CreateDatatable(pStatLyr);

                ISpatialFilter pSF = new SpatialFilterClass();
                pSF.Geometry = pPolygon;
                pSF.GeometryField = m_pClass.ShapeFieldName;
                pSF.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                pSF.WhereClause = pStatLyr.WhereClause1();
                IFeatureCursor pCursor = m_pClass.Search(pSF, false);
                IFeature pFeature = pCursor.NextFeature();

                while (pFeature != null)
                {
                    AddDatarowByFeature(pTable, pFeature, pPolygon, pStatLyr,lyrs,pHash);
                    pFeature = pCursor.NextFeature();
                }
                if (pTable.Rows.Count == 0)
                {
                    MsgHelper.ShowInfomationMsgbox("未检索到符合条件的要素，请重试！");
                    return false;
                }
                FrmReport statReport = new FrmReport();
                //statReport.OnPageMouseDbClick += new DetailSectionEventHandler(OnPageMouseDoubleClick);
                statReport.DataSource = pTable;
                ReportName pName = GetReportname(name, pStatLyr);
                if (pName.HasParameter)
                {
                    IArea pArea = pPolygon as IArea;
                    double area = double.Parse(Math.Abs(pArea.Area).ToString("F3"));
                    statReport.ParameterValue = area;
                }
                statReport.FullName = AppConfig.StartupPath + @"\Report\Statistic\" + pName.Value;
                statReport.Show();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(pCursor);
                return true;
            }
            catch
            {
                MsgHelper.ShowInfomationMsgbox("要素统计失败！");
                return false;
            }
        }

        private double GetVegetableArea(IPolygon pPg, Hashtable pHash)
        {
            try
            {
                foreach (DictionaryEntry de in pHash)
                {
                    string strLyrName = de.Key.ToString();
                    string strDist = de.Value.ToString();
                    StatLayer lyr = StatFactory.GetLayerByID(strLyrName);
                    IFeatureLayer pTempLyr = MapHelper.GetFirstLayer<IFeatureLayer>(m_pMap.Map, strLyrName);
                    if (pTempLyr == null)
                    {
                        MsgHelper.ShowInfomationMsgbox(strLyrName + "未找到！");
                        continue;
                    }
                    ISpatialFilter pFilter = new SpatialFilterClass();
                    ITopologicalOperator pTopo = pPg as ITopologicalOperator;
                    pFilter.Geometry = pTopo.Buffer(double.Parse(strDist));
                    pFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                    pFilter.WhereClause = lyr.WhereClause();
                    IFeatureCursor pCursor = pTempLyr.FeatureClass.Search(pFilter, false);
                    IRelationalOperator pRela = pPg as IRelationalOperator;
                    IFeature pFeature = pCursor.NextFeature();
                    while (pFeature != null)
                    {
                        IGeometry pTempGeo = pFeature.ShapeCopy;
                        ITopologicalOperator pTempTopo = pTempGeo as ITopologicalOperator;
                        IGeometry pTempGeo1 = pTempTopo.Buffer(double.Parse(strDist));
                        if (pRela.Overlaps(pTempGeo1))
                        {
                            pTopo = pPg as ITopologicalOperator;
                            IGeometry pGeo1 = pTopo.Difference(pTempGeo1);
                            if (pGeo1 == null || pGeo1.IsEmpty)
                            {
                                continue;
                            }
                            else
                            {
                                pPg = pGeo1 as IPolygon;
                            }
                        }
                        pFeature = pCursor.NextFeature();
                    }
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(pCursor);
                }
                IArea pArea = pPg as IArea;
                return Math.Abs(pArea.Area);
            }
            catch (Exception ex)
            {
                return 0;
            }
        }

        private StatLayer GetStatLayerByLayername(List<StatLayer> lyrs, string layerName)
        {
            if(lyrs ==null || lyrs.Count ==0)
            {
                return null;
            }
            foreach (StatLayer pLyr in lyrs)
            {
                if (pLyr.LayerName.Equals(layerName))
                {
                    return pLyr;
                }
            }
            return null;
        }

        #region PageEvent
        /// <summary>
        /// 页面双击定位
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        //private void OnPageMouseDoubleClick(object sender, SectionEventArgs e)
        //{
        //    //响应图形选中事件
        //    try
        //    {
        //        if (m_pClass == null) { return; }
        //        if (m_pClass.HasOID == false) { return; }

        //        IFeature pFeat = null;

        //        pFeat = m_pClass.GetFeature(e.GetOID());
        //        if (pFeat == null) { return; }

        //        IActiveView pActiveView = null;

        //        pActiveView = m_pMap.Map as IActiveView;
        //        if (pActiveView == null) { return; }

        //        ZoomToGeometry(pActiveView, pFeat.Shape);
        //        FlashUtility.FlashFeature(pFeat, m_pMap);

        //    }
        //    catch (Exception ex)
        //    {
        //        System.Diagnostics.Trace.TraceInformation("报表页面双击异常: " + ex.ToString());
        //    }
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pActiveView"></param>
        /// <param name="pGeom"></param>
        private void ZoomToGeometry(IActiveView pActiveView, IGeometry pGeom)
        {
            if (pGeom.IsEmpty)
            {
                return;
            }
            IEnvelope pEnvelop = pGeom.Envelope;
            if (pGeom.GeometryType == esriGeometryType.esriGeometryPoint)
            {
                ITopologicalOperator pTopo = pGeom as ITopologicalOperator;
                ISpatialReference pSpatialRef = pGeom.SpatialReference;
                if (pSpatialRef is IGeographicCoordinateSystem)
                {
                    pEnvelop = pTopo.Buffer(0.05).Envelope;
                }
                else
                {
                    pEnvelop = pTopo.Buffer(20).Envelope;
                }
            }
            else
            {
                pEnvelop.Expand(1.5, 1.5, true);
            }
            pActiveView.Extent = pEnvelop;
            pActiveView.Refresh();
            //让缩放完成后，再进行下一步操作，如闪烁
            pActiveView.ScreenDisplay.UpdateWindow();
        }

        #endregion


    }
}
